package dtd.PHS.VND_ExchangeRate;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.util.HashMap;

import android.content.Context;
import android.content.SharedPreferences;
import android.widget.Toast;



public class VCB_ERate {

	static private final String VCB_URL = "http://www.vietcombank.com.vn/en/exchange%20rate.asp";
	static private final String PREVIOUS_LINE = "<tr VALIGN=\"TOP\">";
	static private final String INPUT_DATE_TITLE = "<b>Input date</b>";
	private static final String DATA_STORAGE_FILE = "VCB_ExchangeRate.txt";


//	static public enum MyCurrency {AUD,CAD,CHF,EUR,GBP,HKD,JPY,SGD,THB,USD,VND};	
	static public enum MyCurrency {USD,EUR,AUD,CAD,CHF,GBP,HKD,JPY,SGD,THB,VND};	

	static private HashMap<String, MyCurrency> mapString2Currency;
	static {
		mapString2Currency = new HashMap<String, MyCurrency>();
		mapString2Currency.put("AUD",MyCurrency.AUD);
		mapString2Currency.put("CAD",MyCurrency.CAD);
		mapString2Currency.put("CHF",MyCurrency.CHF);
		mapString2Currency.put("EUR",MyCurrency.EUR);
		mapString2Currency.put("GBP",MyCurrency.GBP);
		mapString2Currency.put("HKD",MyCurrency.HKD);
		mapString2Currency.put("JPY",MyCurrency.JPY);
		mapString2Currency.put("SGD",MyCurrency.SGD);
		mapString2Currency.put("THB",MyCurrency.THB);
		mapString2Currency.put("USD",MyCurrency.USD);
		mapString2Currency.put("VND",MyCurrency.VND);
	}
	
	static public class VND_ExchangeRate {
		public double buying,transfer,selling;
		public MyCurrency currency;
		public VND_ExchangeRate() {						
		}
		public VND_ExchangeRate(MyCurrency c,double buying,double transfer,double selling) {
			this.currency = c;
			this.buying = buying;
			this.transfer = transfer;
			this.selling = selling;
		}
		
	}

	private HashMap<String, VND_ExchangeRate> exchangeRate;
	private String inputDate;

	public VCB_ERate(Context context) {
		initProperties();
		try {
			if ( MyUtility.connectedToInternet(context)) {
				if (isDataUpdated(context)) {
					getRatesFromStorage(context);
				} else {
					getRatesFromURL(context,VCB_URL); 
					storeActualData(context);
					noticeLastOnlineDate(context);
				}
			} else {				
				if (existPastRecords(context)) {
					getRatesFromStorage(context);
				} else	getStaticRates(context);	
				if (! isDataUpdated(context)) {
					Toast toast = Toast.makeText(context, context.getString(R.string.OutDatedWarning), Toast.LENGTH_SHORT );
					toast.show();
				}
			}

		} catch (Exception e) {
			Toast.makeText(context, e.getMessage(), Toast.LENGTH_LONG );
		}

	}

	private boolean existPastRecords(Context context) {
		SharedPreferences settings = 
			context.getSharedPreferences(
					context.getString(R.string.PreferenceName), 
					Context.MODE_PRIVATE);
		String lastOnlineDate = settings.getString(
				context.getString(R.string.LastOnlineDateSetting), null);
		if ( lastOnlineDate != null ) return true;
		return false;
	}

	private boolean isDataUpdated(Context context) {
		SharedPreferences settings = context.getSharedPreferences(context.getString(R.string.PreferenceName), Context.MODE_PRIVATE);
		String lastOnlineDate = settings.getString(context.getString(R.string.LastOnlineDateSetting), null);

		//Have never been online
		if ( lastOnlineDate == null ) return false;

		if ( MyUtility.inThePast(lastOnlineDate) ) return false; 

		return true;
	}




	private void initProperties() {
		exchangeRate = new HashMap<String, VND_ExchangeRate>();
	}

	private void getRatesFromURL(Context context,String URLString) throws Exception {

		URL vcbURL = new URL(URLString);
		BufferedReader in = new BufferedReader(new InputStreamReader(vcbURL.openStream()));
		String inputLine="ABC";
		String previousLine;
		while (inputLine != null) {
			previousLine = inputLine;
			inputLine = in.readLine();
			if ( this.containInputDate(previousLine)) {
				this.extractInputDate(inputLine);
			}
			for (MyCurrency c : MyCurrency.values()) {
				if (this.containsInfoOf(c,inputLine,previousLine)) {
					this.extractCurrencyInfo(c,previousLine,inputLine,in);
				}
			}
		}
		in.close();

	}

	private void storeActualData(Context context) {
		try {
			OutputStreamWriter out = new OutputStreamWriter(
					context.openFileOutput(DATA_STORAGE_FILE,Context.MODE_PRIVATE));
			out.write(this.getInputDate()+"\n");
			for(MyCurrency c: MyCurrency.values()) {
				if ( c.toString().equals(MyCurrency.VND.toString())) continue;
				VND_ExchangeRate rate = this.getVNDRateOf(c);
				out.write(
						c.toString()+"\t"+ 
						Double.toString(rate.buying) + "\t"+
						Double.toString(rate.transfer) + "\t"+
						Double.toString(rate.selling) + "\n" );				
			}
			out.flush();
			out.close();			
		} catch (IOException e) {

		}
	}

	private void noticeLastOnlineDate(Context context) {
		SharedPreferences settings = context.getSharedPreferences(context.getString(R.string.PreferenceName), Context.MODE_PRIVATE);
		SharedPreferences.Editor editor = settings.edit();
		editor.putString(context.getString(R.string.LastOnlineDateSetting), this.inputDate);
		editor.commit();
	}

	private void getRatesFromStorage(Context context) {
		try {
			InputStream in = context.openFileInput(DATA_STORAGE_FILE);
			readFromInputStream(in);
			in.close();
		} catch (IOException e) {

		}
	}
	private void getStaticRates(Context context) {
		try {
			InputStream staticIS = context.getResources().openRawResource(R.raw.exchange_rates);
			readFromInputStream(staticIS);
			staticIS.close();
		} catch (IOException e) {

		}
	}

	private void readFromInputStream(InputStream istream) throws IOException {
		InputStreamReader input = new InputStreamReader(istream);
		BufferedReader buffreader = new BufferedReader(input);

		this.inputDate = buffreader.readLine().trim();				

		String line;		
		while ( (line = buffreader.readLine()) != null ) {
			String[] words = new String[4];
			String[] tempWords = line.split("[ \t\n\f\r]");
			int i = 0;
			for(String word: tempWords) {
				if (word.trim().length() != 0 ) {
					words[i++] = new String(word);
				} 
			}
			//Becarefull with exchange_rates.txt file: only use \t as separator - Else : BUG !
			String currencyName = words[0].trim();
			String buying = words[1].trim();
			String transfer = words[2].trim(); 
			String selling = words[3].trim();

			exchangeRate.put(
					currencyName, 
					new VND_ExchangeRate(
							mapString2Currency.get(currencyName),
							Double.parseDouble(buying), 
							Double.parseDouble(transfer), 
							Double.parseDouble(selling)));

		}
		buffreader.close();
		input.close();
	}

	private void extractInputDate(String inputLine) {		
		this.inputDate = inputLine.substring(
				inputLine.indexOf("value")+7,
				inputLine.indexOf("maxlength")-2);
	}

	private boolean containInputDate(String previousLine) {
		return previousLine.contains(INPUT_DATE_TITLE);		
	}

	public void extractCurrencyInfo(
			MyCurrency c, String previousLine,
			String inputLine, BufferedReader in) {
		try {
			String skipLine = in.readLine();
			String fullCurrencyName = in.readLine();

			double buying = this.extractRateFromLine(in);			
			double transfer = this.extractRateFromLine(in);
			double selling = this.extractRateFromLine(in);

			VND_ExchangeRate excRate = new VND_ExchangeRate(c,buying, transfer, selling);

			this.exchangeRate.put(c.toString(), excRate);


		} catch (Exception e) {
			System.out.println(e.getMessage());			
		}

	}


	private double extractRateFromLine(BufferedReader in) {
		try {
			String skipLine = in.readLine();
			String fullLine = in.readLine();
			int indexBr = fullLine.indexOf("<br>");
			int numberPos = fullLine.lastIndexOf(">", indexBr) + 1;
			String numberString = fullLine.substring(numberPos, indexBr);
			numberString = numberString.replaceAll(",", "");
			return Double.parseDouble(numberString);
		} catch (Exception e) {
			System.out.println(e.getMessage());			
		}
		return 0;
	}

	/**
	 * 
	 * @param c
	 * @param inputLine
	 * @param previuosLine
	 * @return
	 * Note: this method should be private, but it was made to be public for testing purpose
	 */
	public boolean containsInfoOf(MyCurrency c, String inputLine, String previuosLine) {
		if ( ! (previuosLine.trim().equals(PREVIOUS_LINE)) ) {
			return false;
		}
		if (! inputLine.contains(c.toString())) {
			return false;
		}		
		return true;
	}

	public VND_ExchangeRate getVNDRateOf(MyCurrency c) {		
		VND_ExchangeRate rate = this.exchangeRate.get(c.toString());
		return rate;	
	}
	
	public VND_ExchangeRate getVNDRateOf(String cstr) {
		return this.exchangeRate.get(cstr);
	}
	/**
	 * 
	 * @param cFrom
	 * @param cTo
	 * @param amountFrom
	 * @return
	 * Return the amount in the "cto" Currency,
	 * Note: - If the neither "cto" or "cfrom" are VND, 
	 * 		so "cfrom" will be exchanged to VND	and then, 
	 * 		from VND to "cto"
	 */
	public long changeFromTo(
			MyCurrency cFrom,MyCurrency cTo,
			long amountFrom
	) {

		if (cFrom == cTo) return amountFrom;

		//Note: selling > buying for every currency

		//Sell foreign currency for VND - so the bank buys
		if (cTo == MyCurrency.VND) {
			double buyingPricePerUnit = this.exchangeRate.get(cFrom.toString()).buying;
			return Math.round(buyingPricePerUnit*amountFrom);
		}

		//Buy foreign currency with  VND - so the bank sells
		if (cFrom == MyCurrency.VND) {
			double sellingPricePerUnit = this.exchangeRate.get(cTo.toString()).selling;
			return Math.round((1/sellingPricePerUnit) * amountFrom);
		}

		//Neither currencies are VND, so we have to exchange: cFrom->VND->cTo
		long newAmountFrom = changeFromTo(cFrom, MyCurrency.VND, amountFrom);		
		return changeFromTo(MyCurrency.VND, cTo, newAmountFrom);
	}


	public long changeFromToBaseOnTransferRate(
			MyCurrency cFrom,
			MyCurrency cTo,
			long amountFrom
	) {
		if (cFrom == cTo) return amountFrom;
		if (cTo == MyCurrency.VND) {
			double buyingPricePerUnit = this.exchangeRate.get(cFrom.toString()).transfer;
			return Math.round(buyingPricePerUnit*amountFrom);
		}

		if (cFrom == MyCurrency.VND) {
			double sellingPricePerUnit = this.exchangeRate.get(cTo.toString()).transfer;
			return Math.round((1/sellingPricePerUnit) * amountFrom);
		}

		long newAmountFrom = changeFromToBaseOnTransferRate(cFrom, MyCurrency.VND, amountFrom);		
		return changeFromToBaseOnTransferRate(MyCurrency.VND, cTo, newAmountFrom);
	}

	public String getInputDate() {		
		return this.inputDate;
	}

}




